<script setup lang="ts">
import {defineProps, onMounted, ref} from "vue";
import {message} from "ant-design-vue";
import {getValueByPath, setValueByPath} from "../utils/ObjUtils";
import {User} from "../http/Model";
import {PagingHttpService} from "../http/BaseService";

const props = defineProps<{
  service: PagingHttpService<any>,
  editingValueKeyName: string,
  columns: any[],
  editingForm: FormItem[],
  hasPagination?: boolean,
  modalWidth?: number
}>()

const emits = defineEmits(['onRefresh', 'onAddClick', 'onEditClick'])

const service = props.service
const formItems = props.editingForm

const tableContent = ref([])
const tableLoading = ref(false)

// 分页
const pagination = ref({
  current: 1,
  pageSize: 10,
  total: 0
})

const findAllWithPaging = () => {
  const {current, pageSize} = pagination.value
  service.findAllWithPaging!(current, pageSize).then(({data}) => {
    if (data.success) {
      tableLoading.value = false
      const page: Page<User> = data.data
      tableContent.value = page.content
      pagination.value.total = page.total
    } else {
      message.error('列表加载失败')
    }
  })
}

const onPaginationChange = (newPagination: any) => {
  pagination.value = newPagination
  refreshTable()
}

const refreshTable = () => {
  tableLoading.value = true
  if (props.hasPagination) {
    // 分页
    findAllWithPaging()
  } else {
    // 不分页
    service.findAll().then(({data}) => {
      if (data.success) {
        tableLoading.value = false
        tableContent.value = data.data
      } else {
        message.error('列表加载失败')
      }
    })
  }
  emits('onRefresh')
}

onMounted(refreshTable)


// 编辑表单
const editingKey = ref()
const editingValue = ref()
// 当前编辑用户的详细信息
const editingDetail = ref({})

const modalVisible = ref(false)
const modalConfirmLoading = ref(false)
let editingType: "edit" | "add" = "add"

const add = () => {
  editingType = "add"
  editingValue.value = {}
  modalVisible.value = true
  emits('onAddClick')
}

const edit = (record: any) => {
  editingType = "edit"
  editingKey.value = record[props.editingValueKeyName]
  editingValue.value = {}
  service.findOne(editingKey.value).then(({data}) => {
    console.log(data)
    editingDetail.value = data.data
    props.editingForm.forEach((formItem: FormItem) => {
      const temp = getValueByPath(data.data, formItem.dataIndex, null)
      setValueByPath(editingValue.value, formItem.formIndex || formItem.dataIndex, temp)
    })
  })
  modalVisible.value = true
  emits('onEditClick')
}

const saveEditingValue = () => {
  modalConfirmLoading.value = true
  if (editingType === "add") {
    service.newOne(editingValue.value).then(({data}) => {
      modalVisible.value = false
      message.success("创建成功")
      refreshTable()
    }).finally(() => {
      modalConfirmLoading.value = false
    })
  } else if (editingType === "edit") {
    service.update(editingKey.value, editingValue.value).then(({data}) => {
      modalVisible.value = false
      message.success("更新成功")
      refreshTable()
    }).finally(() => {
      modalConfirmLoading.value = false
    })
  }
}

const del = (key: any) => {
  service.delete(key).then(({data}) => {
    message.success("删除成功")
    refreshTable()
  })
}
</script>

<template>
  <!--顶部操作按钮-->
  <p>
    <a-space size="small">
      <a-button type="primary" @click="refreshTable">刷新</a-button>
      <a-button type="primary" @click="add">新建</a-button>
    </a-space>
  </p>
  <!--表格-->
  <a-table :columns="columns" :data-source="tableContent"
           :loading="tableLoading" row-key="id" :pagination="hasPagination?pagination:false"
           @change="onPaginationChange">
    <template #bodyCell="{column, record}">
      <!--自定义列-->
      <slot name="custom-columns" :column="column" :record="record"></slot>
      <!-- 操作 -->
      <template v-if="column.key==='action'">
        <a-space size="small">
          <!--自定义操作-->
          <slot name="custom-action" :column="column" :record="record"></slot>
          <a-button type="primary" @click="edit(record)">
            编辑
          </a-button>
          <a-popconfirm
              title="删除后不可回复，确定删除？"
              ok-text="确认"
              cancel-text="取消"
              @confirm="del(record[props.editingValueKeyName])"
          >
            <a-button type="danger">
              删除
            </a-button>
          </a-popconfirm>
        </a-space>
      </template>
    </template>
  </a-table>
  <!--表单弹窗-->
  <a-modal
      title="编辑"
      cancel-text="取消"
      ok-text="确定"
      :width="modalWidth||520"
      v-model:visible="modalVisible"
      :confirm-loading="modalConfirmLoading"
      @ok="saveEditingValue">
    <a-form
        :model="editingValue"
        name="basic"
        :label-col="{span:6}"
        :wrapper-col="{span:16}"
        autocomplete="off">
      <!--通过列表生成表单-->
      <a-form-item v-for="item in formItems" :label="item.label" :name="item.formIndex||item.dataIndex">
        <!--文本编辑-->
        <template v-if="item.inputType==='text'">
          <a-input v-model:value="editingValue[item.formIndex||item.dataIndex]" :placeholder="item.placeholder"
                   :disabled="!!item.readonly"/>
        </template>
        <!--密码编辑-->
        <template v-else-if="item.inputType==='password'">
          <a-input-password v-model:value="editingValue[item.formIndex||item.dataIndex]"
                            :placeholder="item.placeholder"/>
        </template>
        <!--下拉选择框-->
        <template v-else-if="item.inputType==='select'">
          <a-select
              v-model:value="editingValue[item.formIndex||item.dataIndex]"
              :options="item.options"
              :placeholder="item.placeholder"/>
        </template>
        <!--单选-->
        <template v-else-if="item.inputType==='radio'">
          <a-radio-group v-model:value="editingValue[item.formIndex||item.dataIndex]"
                         :name="item.formIndex||item.dataIndex">
            <a-radio v-for="option in item.options" :value="option.value">{{ option.label }}</a-radio>
          </a-radio-group>
        </template>
      </a-form-item>
    </a-form>
    <slot name="custom-edit" :detail-obj="editingDetail"></slot>
  </a-modal>
</template>